package mc0354;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
//线段树节点
class Tree {
	public int l; // 节点表示区间的左界
	public int r; // 节点表示区间的右届
	//子树区间和有可能超过int范围
	public long val; // 节点数据（0的数量）
	public long lzset; // lazy标记，区间修改数字操作
	public long lzadd; // lazy标记，区间数字加减操作

	public Tree(int l, int r) {
		this.l = l;
		this.r = r;
		// 设置long最大值表示没启用标记
		this.lzset = Long.MAX_VALUE;
	}
}

public class Main {
	public static int N = 100007;
	public static Tree[] t = new Tree[4 * N];
	//public static long[] a = new long[N];

	public static int lc(int p) {
		// 左儿子编号p*2
		return p << 1; // 位运算提高效率
	}

	public static int rc(int p) {
		// 右儿子编号p*2+1
		return p << 1 | 1; // 位运算提高效率
	}

	public static void build(int p, int l, int r) {
		// 实例化节点
		t[p] = new Tree(l, r);
		// l==r则当前节点为叶子，直接存值
		// 叶子节点的l对应原数据的下标
		if (l == r) {
			t[p].val = 0; // 叶子节点初始对应0，0的数量为1
			return;
		}
		// 折半找区间[l,r]的中点
		int mid = (l + r) >> 1;
		// 左儿子递归建树
		build(lc(p), l, mid);
		// 右儿子递归建树
		build(rc(p), mid + 1, r);
		// 从下往上传递区间值，放入节点
		// 此处决定线段树维护区间和或最大值或最小值
		pushUp(p);
	}

	// 从下往上传递区间值，放入节点
	// 此处的p是叶子节点
	private static void pushUp(int p) {
		// 求和，左右子节点val之和
		t[p].val = t[lc(p)].val + t[rc(p)].val;
	}

	// 区间更新、查询与懒操作部分代码
	// 设置lazy标记，注意两个lazy标记间的关系
	// 参数p节点编号
	// 参数v，每个子节点修改后的值
	// 参数op，当前的操作
	public static void lazy(int p, long v, int op) {
		// 取反操作，节点新值为：左右子树长度减去左右子树0的数量
		if (op == 1) {
			// 修改整个区间
			t[p].lzset = v; // 保存修改后的值
			t[p].lzadd = 0; // 覆盖之前的数值加减操作
			// 节点val为，修改后的值乘以当前子树表示的区间长度
			t[p].val = (t[p].r - t[p].l + 1) * v;
		} else {
			// 区间值加减某个数
			t[p].lzadd += v;
			t[p].val += (t[p].r - t[p].l + 1) * v;
			// 之前如果设置了lzset，此处不做操作
		}
	}

	// 向下传递懒标记
	// 参数p节点编号
	public static void pushDown(int p) {
		// 注意修改操作如果有的话要放在前面

		// 区间修改操作
		if (t[p].lzset != Long.MAX_VALUE) {
			lazy(lc(p), t[p].lzset, 1); // 下传左节点
			lazy(rc(p), t[p].lzset, 1); // 下传右节点
			// 复原当前lzset标记
			t[p].lzset = Long.MAX_VALUE;
		}
		// 区间加减操作
		if (t[p].lzadd != 0) {
			lazy(lc(p), t[p].lzadd, 2); // 下传左节点
			lazy(rc(p), t[p].lzadd, 2); // 下传右节点
			// 复原当前lzadd标记
			t[p].lzadd = 0;
		}
	}

	// 区间更新（lazy标记）
	// 参数p节点编号
	// 参数l，r表示将[l,r]区间更新为v
	// 参数op表示哪种操作
	public static void update(int p, int l, int r, long v, int op) {
		// 找到了[l,r]子区间节点
		if (t[p].l >= l && t[p].r <= r) {
			// 更新节点值并设置lazy
			lazy(p, v, op);
			return;
		}
		// [l,r]和节点表示区间有交集的情况
		// 让节点的左右子树去处理
		// 当前节点值的更新是在本方法最后一行回溯时做的
		if (t[p].lzset != Long.MAX_VALUE || t[p].lzadd != 0) {
			// 如果当前节点有lazy标记则下传给子树
			pushDown(p);
		}
		// 折半找区间[t[p].l,t[p].r]的中点
		int mid = (t[p].l + t[p].r) >> 1;
		if (l <= mid)
			update(lc(p), l, r, v, op); // 左子树更新
		if (r > mid)
			update(rc(p), l, r, v, op); // 右子树更新
		// 从下往上更新区间值，放入节点
		// 此处决定线段树维护区间和或最大值或最小值
		pushUp(p);
	}

	// 查询线段树（带lazy标记的情况）
	// 参数p节点编号
	// 参数l，r表示求解的（区间和或最大值或最小值）区间[l,r]
	public static long queryl(int p, int l, int r) {
		// 1、查询区间覆盖节点区间，返回节点值（区简解）
		if (t[p].l >= l && t[p].r <= r) {
			return t[p].val;
		}
		// [l,r]和节点表示区间有交集的情况
		// 让节点的左右子树去处理
		if (t[p].lzset != Long.MAX_VALUE || t[p].lzadd != 0) {
			// 如果当前节点有lazy标记则下传给子树
			pushDown(p);
		}
		// 折半找节点区间[t[p].l,t[p].r]的中点
		int mid = (t[p].l + t[p].r) >> 1;
		long ans = 0;
		// 查询区间和的情况
		// l与左子树有重叠，则进入左子树递归查询
		if (l <= mid)
			ans += queryl(lc(p), l, r);
		// r与右子树有重叠，则进入左子树递归查询
		if (r > mid)
			ans += queryl(rc(p), l, r);
		return ans;
	}

	// 输入优化模板开始
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StreamTokenizer st = new StreamTokenizer(br);

	static int rd() throws IOException {
		st.nextToken();
		return (int) st.nval;
	}
	// 输入优化模板结束
	// 输出优化
	static StringBuilder sb = new StringBuilder();

	public static void main(String[] args) throws IOException {
		int n = rd();
		int m = rd();
		build(1,1,n);
		for(int i=0;i<m;i++) {
			int op = rd();
			int l;
			int r;
			int x;
			if(op==1) {
				l = rd();
				r = rd();
				x = rd();
				update(1,l,r,x,1);
			}else if(op==2) {
				l = rd();
				r = rd();
				x = rd();
				update(1,l,r,x,2);
			}else {
				l = rd();
				r = rd();
				sb.append(queryl(1,l,r));
				sb.append("\n");
			}
		}
		System.out.print(sb.toString());
	}
}
